package wsi.gui.function;

import java.io.File;

import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;

import org.rygh.core.util.UIo;
import org.rygh.gui.model.callback.Callback;
import org.rygh.gui.model.callback.Returnback;
import org.rygh.gui.swing.common.text.STextPresenter;
import org.rygh.gui.swing.common.view.SProgressGlass;
import org.rygh.gui.swing.common.window.xml.SXmlPresenter;
import org.rygh.gui.swing.presenter.SwingPresenter;
import org.rygh.gui.swing.table.STableView;
import org.rygh.semantic.gui.swing.input.Input;
import org.rygh.semantic.gui.swing.input.InputTablePresenter;
import org.rygh.semantic.model.ex.FactSet;

import wsi.db.WebCache;
import wsi.detect.Caller;
import wsi.function.DirManager;
import wsi.function.Function;
import wsi.function.Function.Phrase;
import wsi.function.FunctionController;
import wsi.gui.AppPresenter;
import wsi.gui.tool.DBInjector;
import app.runOnce;

public class FunctionPresenter extends SwingPresenter {

	public interface Display extends SwingPresenter.Display {

		STableView getTable();
	}

	private final static String TITLE = "Function";
	private final SwingPresenter appPresenter;
	private STextPresenter textPresenter;
	private SXmlPresenter xmlPresenter;
	private InputTablePresenter inputTablePresenter;
	private Function function;
	private DirManager dir;
	private FunctionTableModel tableModel;

	public FunctionPresenter(SwingPresenter appPresenter) {
		display = new FunctionWindow(this);

		this.appPresenter = appPresenter;

		bind();
	}

	@Override
	public void close() {
		super.close();
		reset();
	}

	public void doYago() {
		reset();
		tableModel.setValueAt(false, FunctionTableModel.YAGO_ROW,
				FunctionTableModel.BOOL_COL);
		run();
	}

	public void inject() {
		File file = new File(dir.getDebugDir(), "injected_facts.txt");

		if (!file.exists()) {
			getWindow().message("File does not exist.");
			return;
		}

		String content = UIo.readFile(file);
		FactSet facts = new FactSet();
		facts.loadJson(content);

		if (facts.isEmpty()) {
			getWindow().message("No facts to be injected.");
			return;
		}

		DBInjector injector = new DBInjector(this);
		injector.inject(facts);
	}

	public void inputs() {
		reset();
		tableModel.setValueAt(false, FunctionTableModel.INPUTS_ROW,
				FunctionTableModel.BOOL_COL);
		run();
	}

	public void isomorphic() {
		reset();
		tableModel.setValueAt(false, FunctionTableModel.ISOMORPHIC_ROW,
				FunctionTableModel.BOOL_COL);
		run();
	}

	public void load(final Function function) {
		this.function = function;
		dir = new DirManager(function);

		Display d = (Display) display;

		getWindow().setTitle(
				String.format("%s: %s/%s", TITLE, function.getService(),
						function.getName()));

		STableView table = d.getTable();

		tableModel = new FunctionTableModel(function);
		table.setModel(tableModel);

		tableModel.addTableModelListener(new TableModelListener() {

			@Override
			public void tableChanged(TableModelEvent e) {
				tableModel.update(function);
				save();
			}
		});

	}

	public void reset() {
		function.reset();
		tableModel.reload(function);
	}

	public void resolve() {
		reset();
		tableModel.setValueAt(false, FunctionTableModel.RESOLVE_ROW,
				FunctionTableModel.BOOL_COL);
		run();
	}

	public void run() {
		// check if there are multiple tasks scheduled at the same time.
		int count = 0;

		for (Function function : FunctionController.shared().getAllFunctions()) {
			for (Phrase phrase : Function.Phrase.values()) {
				if (phrase == Phrase.REST)
					continue;

				if (!function.isSkipped(phrase))
					count++;
			}
		}

		if (count != 1) {
			getWindow().message("There is not a unique task set: " + count);
			return;
		}

		SProgressGlass<String> progress = getWindow().progress("Running...",
				new Callback<String>() {
					@Override
					public void call(String value) {
						((AppPresenter) appPresenter).setML(value);
					};
				});

		progress.setReturnback(new Returnback<String>() {

			@Override
			public String call() {
				return runOnce.run();
			}
		});
		progress.run();
	}

	public void save() {
		function.save();
	}

	public void viewDataGuide() {
		if (xmlPresenter == null)
			xmlPresenter = new SXmlPresenter();

		String xml = dir.getDataGuideSchema();

		if (xml == null)
			getWindow().message(
					"Cannot load DataGuide for " + function.getName());
		else {
			xmlPresenter.load(xml);
			xmlPresenter.display();
		}
	}

	public void viewInputs() {
		if (inputTablePresenter == null)
			inputTablePresenter = new InputTablePresenter();

		inputTablePresenter.load(dir.getInputs());
		inputTablePresenter.display();

	}

	public void viewInputsMD5() {
		StringBuilder sbuilder = new StringBuilder();

		Input[] inputs = dir.getInputs();
		Caller caller = new Caller(function);

		for (Input i : inputs) {
			String uri = caller.getUri(i.getValue());
			int code = WebCache.getHashCode(uri);

			sbuilder.append(String.format("del %d\r\n", code));
		}

		if (textPresenter == null)
			textPresenter = new STextPresenter();

		textPresenter.load(sbuilder.toString());
		textPresenter.display();
	}
}
